package tech.bmatch.photo.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tech.bmatch.photo.model.Photo;
import tech.bmatch.photo.util.IDUtils;
import tech.bmatch.photo.util.ImageUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

/**
 * 图片服务的实现类
 * 包含上传和下载服务
 * 多用户的额度分配业务
 * 以及用户自行选择打水印的服务
 */
public class PhotoServiceImpl extends PhotoFileStoreServiceImpl {

    /**
     * Logger
     */
    public static final Logger logger = LoggerFactory.getLogger(PhotoServiceImpl.class);
    /**
     * 单个用户最大的可用存储空间 单位byte
     */
    public static final int userMaxSize = 2097152;
    /**
     * 查询单页数量
     */
    public static final int pageSize = 10;
    /**
     * 水印图片位置
     */
    public static final String logoPath = "./images/logo.png";


    /**
     * 检查用户容量并上传文件
     * 和记录图片数据
     *
     * @param files  文件流
     * @param name   文件名称
     * @param userId photo实例
     */
    @Override
    public void upload(byte[] files, String name, String userId) {
        Set<Map.Entry<String, List<Photo>>> entrySet = getPhotosMap().entrySet();
        Iterator<Map.Entry<String, List<Photo>>> iterator = entrySet.iterator();
        long sizeSum = 0;
        while (iterator.hasNext()) {
            Map.Entry<String, List<Photo>> entry = iterator.next();
            if (entry.getKey().equals(userId)) {
                for (Photo photo : entry.getValue()) {
                    sizeSum += photo.getSize();
                }
                break;
            }
        }
        if (sizeSum + files.length > userMaxSize) {
            System.out.println("用户空间不足！");
            System.out.println("用户限定空间：" + userMaxSize / 1024 + "KB");
            System.out.println("本文件大小:" + files.length / 1024 + "kB");
            System.out.println("用户已用容量:" + sizeSum / 1024 + "kB");
            return;
        }

        Photo photo = savePhotoFile(files, name, userId);

        //判断该用户是否没有图片被上传
        if (!getPhotosMap().containsKey(userId)) {
            getPhotosMap().put(userId, new ArrayList<Photo>());
        }
        getPhotosMap().get(userId).add(photo);
        //保存到文件中
        store();
    }

    /**
     * 查询图片
     *
     * @param page   当前页码
     * @param userId 用户ID
     * @return
     */
    @Override
    public List<Photo> query(int page, String userId) {
        Set<Map.Entry<String, List<Photo>>> entrySet = getPhotosMap().entrySet();
        Iterator<Map.Entry<String, List<Photo>>> iterator = entrySet.iterator();
        Map.Entry<String, List<Photo>> entry;
        List<Photo> userPhotoList = null;
        int photoSum = 0;
        while (iterator.hasNext()) {
            entry = iterator.next();
            if (entry.getKey().equals(userId)) {
                userPhotoList = entry.getValue();
                photoSum = userPhotoList.size();
                break;
            }
        }
        if (page > 1 && (page - 1) * pageSize > photoSum) {
            System.out.println("已经超出范围");
            return null;
        }

        List<Photo> photoList;

        int star = pageSize * (page - 1);
        int end = pageSize * page - 1;
        if (end > photoSum - 1) {
            end = photoSum - 1;
        }
        photoList = userPhotoList.subList(star, end + 1);

        return photoList;
    }

    /**
     * 上传图片并储存到随机服务器的目录下
     * 并返回记录的文图片信息
     *
     * @param files 文件流
     * @param name  文件名称
     * @return photo实例
     */
    public Photo savePhotoFile(byte[] files, String name, String userId) {

        // 处理文件存储路径
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/HH/mm/ss");
        String timeStr = sdf.format(System.currentTimeMillis());

        int storeServerIndex = getSeverIndex(getServerCaches().size());
        String severPath = getServerCaches().get(storeServerIndex).getSeverPath();
        String storePath = severPath + "/" + timeStr + "/" + name;

        // 生成图片存储路径
        File storeFile = new File(storePath);
        storeFile.getParentFile().mkdirs(); // 创建层次化目录

        //将字节流存储到文件中，完成文件存储
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(storeFile);
            outputStream.write(files);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("写入文件出错:" + storePath);
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //为图片文件信息测做准备
        BufferedImage sourceImg = null;
        try {
            sourceImg = ImageIO.read(new FileInputStream(storeFile));
        } catch (IOException e) {
            e.printStackTrace();
        }

        Photo photo = new Photo();
        //得到准备数据
        int height = sourceImg.getHeight();
        int width = sourceImg.getWidth();
        Long size = storeFile.length();
        String type = name.substring(name.lastIndexOf(".") + 1);
        Date uploadDate = new Date();

        photo.setHeight(height);
        photo.setWidth(width);
        photo.setName(name);
        photo.setSize(size);
        photo.setStorePath(storeFile.getAbsolutePath());
        photo.setType(type);
        photo.setUploadDate(uploadDate);
        photo.setUserId(userId);
        photo.setWatermark(false);

        String id = IDUtils.getUUID();
        photo.setId(id);

        return photo;
    }


    /**
     * 根据服务器数量，获得随机的服务器索引
     *
     * @param serverCount
     * @return 服务器索引
     */
    public static int getSeverIndex(int serverCount) {
        Random rand = new Random();
        int randomNumber = rand.nextInt();
        if (randomNumber < 0) {
            randomNumber = -randomNumber;
        }
        //通过求余数，分散文件到服务器，达到平衡
        int serverIndex = randomNumber % serverCount;

        return serverIndex;
    }

    /**
     * 用户指定位置打水印
     *
     * @param photoId  图片ID
     * @param position 指定位置
     */
    @Override
    public void doAddWatermark(String photoId, int position, String userId) {
        if (!getPhotosMap().containsKey(userId)) {
            System.out.println("没有该用户的图片");
            return;
        }
        List<Photo> userPhotoList = getPhotosMap().get(userId);
        for (Photo photo : userPhotoList) {
            if (photo.getId().equals(photoId)) {
                if(photo.isWatermark()==true){
                    System.out.println("该图片已经打上了水印");
                    return;
                }
                String imagePath = photo.getStorePath();
                photo.setStorePath(ImageUtils.mergeWaterMark(imagePath,logoPath,position));
                photo.setWatermark(true);
                System.out.println("成功打上水印");
                //保存到文件中
                store();
            }
        }
    }

    /**
     * 去除水印
     * @param photoId 图片ID
     * @param userId 用户ID
     */
    @Override
    public void doClearWatermark(String photoId, String userId){
        if (!getPhotosMap().containsKey(userId)) {
            System.out.println("没有该用户的图片");
            return;
        }
        List<Photo> userPhotoList = getPhotosMap().get(userId);
        for (Photo photo : userPhotoList) {
            if (photo.getId().equals(photoId)) {
                if(photo.isWatermark()==false){
                    System.out.println("该图片还没有打上水印");
                    return;
                }
                String imagePath = photo.getStorePath();
                photo.setStorePath(ImageUtils.clearWaterMark(imagePath));
                photo.setWatermark(false);
                System.out.println("成功去除水印");
                //保存到文件中
                store();
            }
        }
    }
}
